/**
 * Check if a string is a valid hexadecimal color value.
 * Supports formats like #fff and #ffffff.
 * @param {string} color - The color string to check
 * @returns {boolean}
 */
export const isHexColor = (color) => {
    const reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/
    return reg.test(color)
  }
  
  /**
   * Convert RGB values to hexadecimal color string.
   * @param {number} r - Red value (0-255)
   * @param {number} g - Green value (0-255)
   * @param {number} b - Blue value (0-255)
   * @returns {string} Hexadecimal color string (e.g. #ff00ff)
   */
  export const rgbToHex = (r, g, b) => {
    const hex = ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')
    return `#${hex}`
  }
  
  /**
   * Convert HEX color to RGB or RGBA string.
   * @param {string} hex - The hex color string
   * @param {number} [opacity] - Optional opacity value (0-1)
   * @returns {string} RGB or RGBA color string
   */
  export const hexToRGB = (hex, opacity) => {
    if (!isHexColor(hex)) return hex
    
    let sHex = hex.toLowerCase().replace('#', '')
    
    // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
    if (sHex.length === 3 || sHex.length === 4) {
      sHex = sHex.split('').map(c => c + c).join('')
    }
    
    const r = parseInt(sHex.substring(0, 2), 16)
    const g = parseInt(sHex.substring(2, 4), 16)
    const b = parseInt(sHex.substring(4, 6), 16)
    
    if (typeof opacity === 'number') {
      return `rgba(${r}, ${g}, ${b}, ${opacity})`
    }
    return `rgb(${r}, ${g}, ${b})`
  }
  
  /**
   * Check if a color is dark.
   * @param {string} color - Hex color string
   * @returns {boolean}
   */
  export const colorIsDark = (color) => {
    if (!isHexColor(color)) return false
    
    const rgb = hexToRGB(color)
      .replace(/[^\d,]/g, '')
      .split(',')
      .map(Number)
    
    const [r, g, b] = rgb
    return r * 0.299 + g * 0.587 + b * 0.114 < 150
  }
  
  /**
   * Darken a HEX color by percentage.
   * @param {string} color - Hex color string
   * @param {number} amount - Percentage to darken (0-100)
   * @returns {string} Darkened hex color
   */
  export const darken = (color, amount) => {
    const hex = color.replace('#', '')
    const amt = Math.round(2.55 * amount)
    
    const r = Math.max(0, parseInt(hex.substring(0, 2), 16) - amt).toString(16).padStart(2, '0')
    const g = Math.max(0, parseInt(hex.substring(2, 4), 16) - amt).toString(16).padStart(2, '0')
    const b = Math.max(0, parseInt(hex.substring(4, 6), 16) - amt).toString(16).padStart(2, '0')
    
    return `#${r}${g}${b}`
  }
  
  /**
   * Lighten a HEX color by percentage.
   * @param {string} color - Hex color string
   * @param {number} amount - Percentage to lighten (0-100)
   * @returns {string} Lightened hex color
   */
  export const lighten = (color, amount) => {
    const hex = color.replace('#', '')
    const amt = Math.round(2.55 * amount)
    
    const r = Math.min(255, parseInt(hex.substring(0, 2), 16) + amt).toString(16).padStart(2, '0')
    const g = Math.min(255, parseInt(hex.substring(2, 4), 16) + amt).toString(16).padStart(2, '0')
    const b = Math.min(255, parseInt(hex.substring(4, 6), 16) + amt).toString(16).padStart(2, '0')
    
    return `#${r}${g}${b}`
  }
  
  /**
   * Calculate luminance of an RGB color.
   * @param {number} r - Red value (0-255)
   * @param {number} g - Green value (0-255)
   * @param {number} b - Blue value (0-255)
   * @returns {number} Luminance value
   */
  const luminanace = (r, g, b) => {
    const a = [r, g, b].map(v => {
      v /= 255
      return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4)
    })
    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722
  }
  
  /**
   * Calculate contrast ratio between two RGB colors.
   * @param {number[]} rgb1 - First RGB color as array
   * @param {number[]} rgb2 - Second RGB color as array
   * @returns {number} Contrast ratio
   */
  const contrast = (rgb1, rgb2) => {
    return (luminanace(...rgb1) + 0.05) / (luminanace(...rgb2) + 0.05)
  }
  
  /**
   * Determine the best text color (black or white) based on background contrast.
   * @param {string} hexColor - Background color in hex format
   * @returns {string} '#000000' or '#FFFFFF'
   */
  export const calculateBestTextColor = (hexColor) => {
    const rgb = hexToRGB(hexColor)
      .replace(/[^\d,]/g, '')
      .split(',')
      .map(Number)
    
    const contrastWithBlack = contrast(rgb, [0, 0, 0])
    return contrastWithBlack >= 3 ? '#000000' : '#FFFFFF'
  }
  
  /**
   * Mix two colors by weight.
   * @param {string} color1 - First hex color
   * @param {string} color2 - Second hex color
   * @param {number} [weight=0.5] - Weight of first color (0-1)
   * @returns {string} Mixed hex color
   */
  export const mix = (color1, color2, weight = 0.5) => {
    const hex1 = color1.replace('#', '')
    const hex2 = color2.replace('#', '')
    
    let mixed = '#'
    for (let i = 0; i <= 2; i++) {
      const c1 = parseInt(hex1.substring(i * 2, i * 2 + 2), 16)
      const c2 = parseInt(hex2.substring(i * 2, i * 2 + 2), 16)
      const c = Math.round(c1 * weight + c2 * (1 - weight))
      mixed += c.toString(16).padStart(2, '0')
    }
    
    return mixed
  }